open Ocamlbuild_plugin

let version = "0.4.1+dev"
let authors = "[\"Makarov A.I.\"; ]"
let license = "GNU LGPL"
let get_license_text = "
    (try
        let ich = open_in \"/usr/share/common-licenses/LGPL\" in
        let len = in_channel_length ich in
        let buf = Buffer.create len in
        Buffer.add_channel buf ich len;
        close_in ich;
        Buffer.contents buf
    with _ ->
        (\"Licensed under GNU LGPL \n\"^
        \"http://www.gnu.org/copyleft/lesser.html\")
    )"
;;

let current_dir = Sys.getcwd ()
let () =
(*    let conf = Filename.concat "TTree_convert" "config.ml" in*)
    let conf = "OKAHEP_config.ml" in
    let out_file = open_out conf in
    let out str = output_string out_file str; output_string out_file "\n" in
    let quot s1 s2 = out (Printf.sprintf "let %s = \"%s\"" s1 s2) in
    quot "version" version; quot "license" license;
    out ("let authors = "^authors);
    out ("  let license_text () = "^get_license_text);
    out
      (Printf.sprintf 
      "let install_dir = Filename.concat \"%s\" \"_build\"" 
      current_dir);
    out
      (Printf.sprintf 
      "let ottree_gen_dir = Filename.concat \"%s\" \"TTree_convert\"" 
      current_dir);
    close_out out_file
;;

(* these functions are not really officially exported *)
let run_and_read = Ocamlbuild_pack.My_unix.run_and_read
let blank_sep_strings = Ocamlbuild_pack.Lexers.blank_sep_strings

let split s ch =
  let x = ref [] in
  let rec go s =
    let pos = String.index s ch in
    x := (String.before s pos)::!x;
    go (String.after s (pos + 1))
  in
  try
    go s
  with Not_found -> !x
                                                                                                                                                                                                                                             
let split_nl s = split s '\n'

let before_space s =
  try
    String.before s (String.index s ' ')
  with Not_found -> s

(* this lists all supported packages *)
let find_packages () =
  List.map before_space (split_nl & run_and_read "ocamlfind list")

let find_pkg_config_packages () =
  List.map before_space (split_nl & run_and_read "pkg-config --list-all")
;;

let lst_pkg_config_packages = [ "plplotd"; "gtk+-x11-2.0"; ]

(* this is supposed to list available syntaxes, but I don't know how to do it. *)
let find_syntaxes () = ["camlp4o"; "camlp4r"]

(* ocamlfind command *)
let ocamlfind x = S[A"ocamlfind"; x]

let _ = dispatch begin function
   | Before_options ->
       (* by using Before_options one let command line options have an higher priority *)
       (* on the contrary using After_options will guarantee to have the higher priority *)

       (* override default commands by ocamlfind ones *)
       Options.ocamlc     := ocamlfind & A"ocamlc";
       Options.ocamlopt   := ocamlfind & A"ocamlopt";
       Options.ocamldep   := ocamlfind & A"ocamldep";
       Options.ocamldoc   := ocamlfind & A"ocamldoc";
       Options.ocamlmktop := ocamlfind & A"ocamlmktop"

   | After_rules ->

       (* When one link an OCaml library/binary/package, one should use -linkpkg *)
(*       flag ["ocaml"; "link"; "program"] & A"-linkpkg";*)
       flag ["ocaml"; "link"; "byte"; ] & A"-linkpkg";
       flag ["ocaml"; "link"; "native"; ] & A"-linkpkg";
       flag ["ocaml"; "link"; ] & A"-thread";
       flag ["link"; "library"; "ocaml"; "byte";]
               (S[A"gtkThread.cmo";A"gtkInit.cmo";]);
       flag ["link"; "library"; "ocaml"; "native";]
               (S[A"gtkThread.cmx";A"gtkInit.cmx";]);
(*       flag ["ocaml"; "link"; ] & A"gtkThread.cmo";
       flag ["ocaml"; "link"; ] & A"gtkInit.cmo";*)

(*       ocaml_lib "gtk_pldraw_ev";*)
(*       let libgtk_pldraw_ev_stubs = "gtk_pldraw_ev_stubs." ^ !Options.ext_lib in
       print_endline libgtk_pldraw_ev_stubs;
       flag ["link"; "ocaml"; "gtk_pldraw_ev"] 
                (S[A"-cclib"; A libgtk_pldraw_ev_stubs;]);
       dep  ["link"; "ocaml"; "gtk_pldraw_ev"] [libgtk_pldraw_ev_stubs];
*)
(*       dep ["ocaml"; "link"; ] ["libgtk_pldraw_ev.a"];
       dep ["libgtk_pldraw_ev.a"] ["gtk_pldraw_ev.c"];
       flag ["c"; "compile" ]  & S[A"ocamlc"];*)
(*       dep  ["link"; "ocaml"; ] ["libgtk_pldraw_ev"];*)


            List.iter
              (fun (lib, dir, headers) ->
                   (* Handle C part of library *)
                   flag ["link"; "library"; "ocaml"; "byte"; "use_lib"^lib]
                     (S[A"-dllib"; A("-l"^lib); A"-cclib"; A("-l"^lib)]);
  
                   flag ["link"; "library"; "ocaml"; "native"; "use_lib"^lib]
                     (S[A"-cclib"; A("-l"^lib)]);
                        
                   flag ["link"; "program"; "ocaml"; "byte"; "use_lib"^lib]
                     (S[A"-dllib"; A("dll"^lib)]);
  
                   (* When ocaml link something that use the C library, then one
                      need that file to be up to date.
                    *)
                   let lib_path = dir/"lib"^lib^"."^(!Options.ext_lib) in
                   dep  ["link"; "ocaml"; "use_lib"^lib] 
                     [lib_path];

(*                   flag ["ocaml"; "link"; ] & S[A lib_path];*)
  
                   (* TODO: be more specific about what depends on headers *)
                   (* Depends on .h files *)
                   dep ["compile"; "c"] 
                     headers;
  
                   (* Setup search path for lib *)
                   flag ["link"; "ocaml"; "use_"^lib] 
                     (S[A"-I"; P(dir)]);
              )
              ["gtk_pldraw_ev","gui",[]];

       (* For each ocamlfind package one inject the -package option when
        * compiling, computing dependencies, generating documentation and
        * linking. *)
       List.iter begin fun pkg ->
         flag ["ocaml"; "compile";  "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["c"; "compile";  "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["ocaml"; "doc";      "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["ocaml"; "link";     "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["c"; "link";     "pkg_"^pkg] & S[A"-package"; A pkg];
         flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S[A"-package"; A pkg];
       end (find_packages ());

(*       flag ["c"; "compile"; ] & S[A "-h"];*)
       List.iter begin fun pkg ->
           let cmd = "`pkg-config --cflags --libs "^pkg^" `" in
           flag ["c"; "compile";  "c_pkg_"^pkg] & S[A"-ccopt"; A cmd];
           flag ["c"; "link";     "c_pkg_"^pkg] & S[A"-ccopt"; A cmd];
       end lst_pkg_config_packages;
(*       end (find_pkg_config_packages ());*)

       (* Like -package but for extensions syntax. Morover -syntax is useless
        * when linking. *)
       List.iter begin fun syntax ->
         flag ["ocaml"; "compile";  "syntax_"^syntax] & S[A"-syntax"; A syntax];
         flag ["ocaml"; "ocamldep"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
         flag ["ocaml"; "doc";      "syntax_"^syntax] & S[A"-syntax"; A syntax];
         flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & S[A"-syntax"; A syntax];
       end (find_syntaxes ());
       
       (* The default "thread" tag is not compatible with ocamlfind.
          Indeed, the default rules add the "threads.cma" or "threads.cmxa"
          options when using this tag. When using the "-linkpkg" option with
          ocamlfind, this module will then be added twice on the command line.
       
          To solve this, one approach is to add the "-thread" option when using
          the "threads" package using the previous plugin.
        *)
       flag ["ocaml"; "pkg_threads"; "compile"] (S[A "-thread"]);
       flag ["ocaml"; "pkg_threads"; "link"] (S[A "-thread"]);
       flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"])
       
   | _ -> ()
end

